Dagger

依赖注入概念

依赖注入(Dependency Injection),简称 DI,又叫控制反转(Inversion of Control),简称 IOC。简言之,目标类(需要进行依赖初始化的类)中所依赖的其他的类的初始化过程,不是通过手段编码方式创建,而是通过技术手段,把其他类已经初始化好的实例自动注入到目标类。Dagger2 就是实现依赖注入的一种技术手段。

Dagger2 实质: 就是帮我们写工厂代码,当然比工厂模式更加强大

依赖注入概念

1、依赖概念

一个类的实例需要另一个类的实例进行协助时。传统的设计,通常由调用者来创建被调用者的实例。

如:一个类 ClassA 中,有一个类 ClassB 的实例,则称 ClassA 对 ClassB 有一个依赖。依赖在构造方法中直接 hard init。

public class ClassA {
    ClassB classB;
    public ClassA(){
       classB = new ClassB();
    }
}

2、依赖注入

除了上面的传统依赖方式。创建被调用者不再由调用者创建实例,创建被调用者的实例工作由 IOC 容器来完成,然后注入到调用者中,这个叫做依赖注入。

将 classB 对象作为 ClassA 构造方法的一个参数传入,在调用 ClassB 的构造方法时已经初始化好了 ClassA 对象了。这种非自己主动初始化依赖,而通过外部传入依赖的方式,称之为依赖注入。

public class ClassA {
    ClassB classB;
    public ClassA(ClassB classB){
       this.classB = classB;
    }
}

Dagger2

Dagger2 介绍

Dagger2 使用注解来实现依赖注入,但它利用 APT(Annotation Process Tool) 在编译时生成辅助类,这些类继承特定父类或实现特定接口,程序在运行时 Dagger2 加载这些辅助类,调用相应接口完成依赖生成和注入。没有用到运行时反射,对性能影响很小。

取名

Dagger 这个库的取名不仅仅来自它的本意 " 匕首 ",同时也暗示了它的原理。Jake Wharton 在对 Dagger 的介绍中指出,Dagger 即 DAG-er,这里的 DAG 即数据结构中的 DAG——有向无环图 (Directed Acyclic Graph)。也就是说,Dagger 是一个基于有向无环图结构的依赖注入库。

优点

  1. 将类的初始化以及类之间的依赖关系集中在一处处理
  2. 有大量类的初始化,以及类之间的依赖关系很复杂的时候

Reference

Dagger2 之注解详解

Dagger2 中的注解介绍

对象之间的互相依赖可以想象成一个有向无环图。描述这个图,可以像 Spring 框架一样用一个配置文件来描述依赖关系,Dagger2 用注解来描述依赖关系,更加的直接清晰。

Dagger2 中的注解

  1. @Inject 注解标记在一个属性上,表示该属性需要依赖(表现在目标类中需要依赖被注入一个对象)
  2. @Inject 注解标记在一个构造方法上,表示该构造方法可以提供依赖。
  1. 注解在类的构造方法上,这个类的构造方法只能有一个有 @Inject
  2. 注解在类的属性上,该属性不能 private 修饰
  3. 注解在构造方法上,如果注解的构造方法 AClass() 是带参数 BClass 的,那么会去 Module 类中检查是否有返回 BClass 参数的方法,或者 BClass 是否有被@Inject 注解的构造函数,如果没有找到会在编译期报错(这在编译期保证了对象之间的依赖被满足)
 public class AClass{
    @Inject
    public AClass(BClass bClass){
        //do something
    }
 }
  1. 接口是没有构造方法的,不能对构造方法进行注解
  2. 第三方库提供的类,我们无法修改源码,也不能注解它们的构造方法
  3. 有些类需要提供统一的生成方法 (一般会同时私有化构造方法) 或需要动态选择初始化的配置,而不是使用一个单一的构造方法
  1. 谁来提供依赖
  2. 该 Component 依赖哪些其他的 Component
  3. 该 Component 为谁提供依赖注入
  4. 该 Component 可以提供哪些依赖
@Singleton
@Component(modules = {AppModule.class},dependencies = {xxxComponent.class})
public interface AppComponent{
  void inject(MyActivity myActivity);
  public MyApplication getApplication();
}
  1. modules 参数{}里的类就表示提供依赖的 Module 类(可以有多个),也就是用 @Module 注解的类
  2. dependencies 表示该 Component 提供的注入类的构造函数中,还依赖其他 @Component 提供的一些类
  3. 有参无反的方法指明该参数为 Component 注入的目标,比如本例中,就说明 MyActivity 中需要 AppComponent 提供的依赖
  4. 有反无参的方法指明该 Component 可以提供哪些依赖,或者说暴露哪些依赖。因为这里可能会有疑问,Component 可提供的依赖不就是 Module 里的那些吗?确实没错,但是 Component 也可以有选择的只对外界暴露它的一部分能力,并不一定会声明所有的在 Module 里定义的类。
  5. 这个接口可以理解成一份声明,告诉 Dagger 哪些对象可以被注入,以及谁(Module 类中被@Provides 注解的方法)来提供这些依赖。需要注意,只有在 Component 接口中声明了的类,才会被暴露给依赖它的其他 Component。也就是说,Module 类中提供的依赖,并不一定都会在 Component 中声明。
  1. @Component 修饰的必须是接口或抽象类。Dagger2 框架将自动生成 @Component 的实现类,对应类名 DaggerXXX(XXX 为你的 Component 类)。添加的注入方法一般使用 inject() 方法名,需要一个参数对应为需要注入依赖的容器的实例。
  2. 如果 Component 中的某个对象具有 Scope(Module 中的一个方法具有 Scope),那么该 Component 也具有 Scope。
  1. 通过@Inject 注解标注的构造方法来创建
  2. 通过@Module 工厂模式来创建
    这 2 个纬度是有优先级的,@Component 会首先从@Module 维度中查找类实例,若找到就用@Module 维度创建类实例,并停止查找@Inject 维度。否则才是从@Inject 维度查找类实例。所以创建类实例级别@Module 维度要高于@Inject 维度。
  1. 更好的管理 Component 之间的组织方式,不管是依赖方式还是包含方式,都有必要用自定义的@Scope 注解标注这些 Component,这些注解最好不要一样,这样可以更好的体现出 Component 之间的组织方式。还有编译器检查有依赖关系或包含关系的 Component,若发现有 Component 没有用自定义@Scope 注解标注,会报错。
  2. 更好的管理 Component 与 Module 之间的匹配关系,编译器会检查 Component 管理的 modules,若发现标注 Component 的自定义@Scope 注解与 modules 中的标注创建依赖类实例方法的注解不一样,会报错。
  3. 可读性提高,如用@Singleton 标注全局依赖类,立马能明白这类是全局单例类。
  1. 一个 Module 里只能存在一种 Scope
  2. 如果两个 Component 间有依赖关系 (dependencies),那么它们不能使用相同的 Scope,即不同的 Component 之间的 Scope 必须不同
  3. Singleton 的 Component 不能依赖其他 Scope 的 Component,只能其他 Scope 的组件依赖 Singleton 的 Component
  4. 没有 Scope 的 Component 不能依赖有 Scope 的 Component
  5. 一个 Component 不能同时有多个 Scope,SubComponent 除外
  6. Dagger2 框架不会帮你管理对象的生命周期,需要自己来控制
  1. ApplicationComponent 管理 Module
  2. 保证 ApplicationComponent 只有一个实例(在 app 的 Application 中实例化 ApplicationComponent)
  1. 更好的管理 ApplicationComponent 和 Module 之间的关系,保证 ApplicationComponent 和 Module 是匹配的。若 ApplicationComponent 和 Module 的 Scope 是不一样的,则在编译时报错
  2. 代码可读性,让程序员更好的了解 Module 中创建的依赖类实例是单例的

子 Component
和 Component 的 dependencies 区别:
dependencies 不会继承范围(Scope),但 SubComponent 会继承 Scope,这样 SubComponent 同时具备了两种 Scope

是一个 @Qualifier,如果 Module 中需要生成同一个类的两个不同实例,需要用 @Named,根据 @Named 后面字符串来匹配需要注入哪种实例,

@Provides
@Named("default")
SharedPreferences provideDefaultSharedPrefs() { /*…*/ }

@Provides
@Named("secret")
SharedPreferences provideSecretSharedPrefs() {/*…*/ }

提供两种不同的 SharedPreferences 依赖,在需要注入的地方这样标记:

@Inject @Named("default")
SharedPreferences mDefaultSharedPrefs;
@Inject @Named("secret")
SharedPreferences mSecretSharedPrefs;
10、Lazy 接口和 Provider 接口

见 Dagger2 之 Lazy 和 Provider.md

11、Multibindings

Multibindings 的应用场景比较少,主要用于插件化的实现,Multibindings 分成 Set 与 Map,Map 的 Multibindings 目前还是 Beta 版本,也就是说还是在试验阶段,所以只介绍简单的 Set 的 Multibindings。
通过 Multibindings,Dagger 可以将不同 Module 产生的元素整合到同一个集合。更深层的意义是,Module 在此充当的插件的角色,客户端通过这些插件的不同而获取到不同的集合。

其他

1、@Inject 和@Provides 依赖生成方式的区别

Dagger2 之 Component

一、Component 的组织方式(重点)

2、划分规则
3、划分粒度不能过小

假如使用 mvp 架构搭建 app,划分粒度是基于每个页面的 m、v、p 各自定义 Component 的,那 Component 的粒度就太小了,定义这么多的 Component,管理、维护就很非常困难
所以以页面划分 Component 在管理、维护上面相对来说更合理。

二、组织 Component

问题:其他的 Component 想要全局的依赖类实例,涉及到了依赖类实例共享问题。因为 Component 有管理创建类实例的能力。因此只要能很好的组织 Component 之间的关系,问题就好办了,具体的组织方式分为以下 3 种:

依赖方式

一个 Component 是依赖于一个或多个 Component,Component 的 dependencies 属性就是依赖方式的具体体现。

包含方式

一个 Component 是包含一个或多个 Component 的,被包含的 Component 还可以继续包含其他的 Component。这种方式特别像 Activity 与 Fragment 的关系。SubComponent 就是包含方式的具体体现。

继承方式

官网没有提到该方式,具体没有提到的原因我觉得应该是,该方式不是解决类实例共享的问题,而是从更好的管理、维护 Component 的角度,把一些 Component 共有的方法抽象到一个父类中,然后子 Component 继承。

三、SubComponent

如果一个 Component 的功能不能满足你的需求,你需要对它进行拓展,一种办法是使用 Component(dependencies=××.classs)。另外一种是使用 @Subcomponent,Subcomponent 用于拓展原有 component。同时,这将产生一种副作用——子 component 同时具备两种不同生命周期的 scope。子 Component 具备了父 Component 拥有的 Scope,也具备了自己的 Scope。
Subcomponent 其功能效果优点类似 component 的 dependencies。但是使用@Subcomponent 不需要在父 component 中显式添加子 component 需要用到的对象,只需要添加返回子 Component 的方法即可,子 Component 能自动在父 Component 中查找缺失的依赖。
父 AppComponent:

@PerApp
@Component(modules = {AppModule.class})
public interface AppComponent { //父Component
    ActivitySubComponent subAppComponent();  //1.只需要在父Component添加返回子Component的方法即可
}

子 ActivitySubComponent:

@PerActivity //2.注意子Component的Scope范围小于父Component
@Subcomponent(modules = {ActivityModule.class})//3.使用@Subcomponent
public interface ActivitySubComponent {  //子Component
    void inject(SubcomponentDemoActivity subcomponentDemoActivity);
}

使用:

// 4.调用subComponent方法创建出子Component
DaggerAppComponent
        .builder()
        .appModule(new AppModule())
        .build()
        .subAppComponent()
        .inject(this);

// 通过调用父Component
String runningActivityName = mActivityInfo.runningActivityName();
// 通过ActivitySubComponent
AppInfo appInfo = mActivityInfo.mAppInfo();

通过 Subcomponent,子 Component 就好像同时拥有两种 Scope,当注入的元素来自父 Component 的 Module,则这些元素会缓存在父 Component;当注入的元素来自子 Component 的 Module,则这些元素会缓存在子 Component 中。

Dagger2 之 Lazy 和 Provider 接口

Lazy 和 Provider 都是用于包装目标类中需要被注入的类型

Lazy

Lazy 用于延迟加载,在 get() 的时候,才会创建对象,后面每次 get() 都是一样的对象。

Provider

Provider 用于强制重新加载,Provider 保证每次重新加载,但并不意味着每次返回的对象都是不同的,只有 Module 的@Provide 方法每次都创建新的实例时,Provider 每次 get() 的对象才相同。

案例

@Component(modules = {CounterModule.class})
public interface CounterComponent {
//    不能用父类或父接口
//    void inject(Counter counter);
    void inject(DirectCounter counter);
    void inject(LazyCounter counter);
    void inject(ProviderCounter counter);
}
 @Module
 public class CounterModule {
    int next = 100;
    private final String type;
    public CounterModule(String type) {
        this.type = type;
    }
    @Provides
    public Integer provideInteger() {
        Log.i(Counter.TAG, type + " computing...");
        return next++;
    }
 }
 public class DirectCounter extends Counter {
    @Inject
    Integer value;
    @Override
    public void init() {
        DaggerCounterComponent.builder().counterModule(new CounterModule(this.getClass().getSimpleName())).build().inject(this);
    }
    @Override
    public void log() {
        super.log();
        logi(value.toString());
        logi(value.toString());
        logi(value.toString());
    }
 }
// DirectCounter computing
// DirectCounter printing...
// 100
// 100
// 100
 public class LazyCounter extends Counter {
    @Inject
    Lazy<Integer> lazy;
    @Override
    public void init() {
        DaggerCounterComponent.builder().counterModule(new CounterModule(this.getClass().getSimpleName())).build().inject(this);
    }
    @Override
    public void log() {
        super.log();
        logi(lazy.get().toString()); //在这时才创建对象,以后每次调用get会得到同一个对象
        logi(lazy.get().toString());
        logi(lazy.get().toString());
    }
 }
// LazyCounter printing...
// LazyCounter computing...
// 100
// 100
// 100
 public class ProviderCounter extends Counter {
    @Inject
    Provider<Integer> provider;
    @Override
    public void init() {
        DaggerCounterComponent.builder().counterModule(new CounterModule(this.getClass().getSimpleName())).build().inject(this);
    }
    @Override
    public void log() {
        super.log();
        logi(provider.get().toString()); //在这时创建对象,以后每次调用get会再强制调用Module的Provides方法一次,根据Provides方法具体实现的不同,可能返回跟前面的是同一个对象,也可能不是。
        logi(provider.get().toString());
        logi(provider.get().toString());
    }
 }
// ProviderCounter printing...
// ProviderCounter computing...
// 100
// ProviderCounter computing...
// 101
// ProviderCounter computing...
// 102

Dagger2 之注意点及易错点

一、Dagger2 使用注意点

1、为@Provides 方法添加输入参数

Module 中@Provides 方法可以带输入参数,其参数由 Module 集合中的其他@Provides 方法提供,或者自动调用@Inject 的构造方法;如果找不到@Provides 方法提供对应参数的对象,自动调用带@Inject 参数的构造方法生成相应对象

2、添加多个 Module

一个 Component 可以包含多个 Module,这样 Component 获取依赖时候会自动从多个 Module 中查找获取,Module 间不能有重复方法。添加多个 Module 有两种方法,一种是在 Component 的注解@Component(modules={××××,×××}) 添加多个 modules,

@Component(modules={ModuleA.class,ModuleB.class,ModuleC.class}) //添加多个Module
public interface FruitComponent{
    // ...
}

另外一种添加多个 Module 的方法可以被使用 Module 中的@Module(includes={××××,×××}),这种使用 Module 的 includes 的方法一般用于构建更高层的 Module 时候使用。

@Module(includes={ModuleA.class,ModuleB.class,ModuleC.class})
public class FruitModule{
    // ...
}
@Component(modules={FruitModule.class}) //添加多个Module
public interface FruitComponent{
    // ...
}
3、DaggerXXXComponent.create()--Module 实例的创建
DaggerFruitComponent.create().inject(this); //7 使用FruitComponent的实现类注入
// 等价于
DaggerFruitComponent.builder().appleModule(new AppleModule()).bananaModule(new BananaModule()).build().inject(this);

调用 DaggerFruitComponent.create() 实际上等价于 DaggerFruitComponent.builder().build()。DaggerFruitComponent 使用了构建者模式,在构建的过程中,默认使用了 Module 无参的构造方法产生实例。

public FruitComponent build() {
  if (appleModule == null) {
    this.appleModule = new AppleModule();
  }
  if (bananaModule == null) {
    this.bananaModule = new BananaModule();
  }
  return new DaggerFruitComponent(this);
}

**Note: **如果需要传入特定的 Module;使用 Module 的有参构造器,那么必须显示传入 Module 实例。

4、区分返回类型相同的@Providers 修饰的方法

当有 Fruit 需要注入时,Dagger2 就会在 Module 中查找返回类型为 Fruit 的方法,也就是说,Dagger2 是按照 Provide 方法返回类型查找对应的依赖。但是,当 Container 需要依赖两种不同的 Fruit 时,你就需要写两个@Provides 方法,而且这两个@Provides 方法都是返回 Fruit 类型,靠判别返回值的做法就行不通了,编译时报如下错误:

Error:(20, 10) 错误: me.hacket.thirdpart.dagger2.demo3.bean.Fruit is bound multiple times:
@Provides me.hacket.thirdpart.dagger2.demo3.bean.Fruit me.hacket.thirdpart.dagger2.demo3.module.FruitModule.provideApple()
@Provides me.hacket.thirdpart.dagger2.demo3.bean.Fruit me.hacket.thirdpart.dagger2.demo3.module.FruitModule.provideBanana()
@Provides me.hacket.thirdpart.dagger2.demo3.bean.Fruit me.hacket.thirdpart.dagger2.demo3.module.AppleModule.provideFruit(int)

这就需要使用@Named 来区分,只有具有相同 @Named 注解标记的目标类中@Inject 和生成依赖类中 Module 的@Provides 对应起来。

//定义Module
@Module
public class FruitModule{
    @Named("typeA")
    @Provides
    public Fruit provideApple(){  //提供Apple给对应的mFruitA
        return new Apple();
    }
    @Named("typeB")
    @Provides
    public Fruit provdeBanana(){ //提供Banana给对应的mFruitB
        return new Banana()
    }
}
//定义Component
@Component(modules={FruitModule.class})
interface FruitComponent{    //Dagger根据接口自动生成FruitComponent
    void inject(Container container);
}
//定义Container
class Container{
    @Named("typeA") //添加标记@Name("typeA"),只获取对应的@Name("typeA")的元依赖
    @Inject
    Fruit mFruitA;
    @Named("typeB") //添加标记@Name("typeA"),只获取对应的@Name("typeA")的依赖
    @Inject
    Fruit mFruitB;
    // ...
    public void init(){
         DaggerFruitComponent.creaete().inject(this); //使用FruitComponent的实现类注入
     }

}

如果觉得@Named 只能用字符串区分不满足需求,你也可以自定义类似@Named 的注解,使用元注解@Qualifier 可以实现这种注解,比如实现一个用 int 类型区分的@IntNamed,用法同@Named 注解一样:

@Qualifier // 必须,表示IntNamed是用来做区分用途
@Documented // 规范要求是Documented,当然不写也问题不大,但是建议写,做提示作用
@Retention(RetentionPolicy.RUNTIME) // 规范要求是Runtime级别
public @interface IntNamed{
    int value();
}
5、Component 定义方法的规则
@Component(modules = {FruitModule.class, AppleModule.class, BananaModule.class})
public interface FruitComponent {
    void inject(Container container);
}
//定义ComponentB
@Component(modules={××××××××})//1.假设Module中没有provideApp()方法,但有provideInfo()
interface ComponentB{
    Apple apple(); //2.实现类自动返回由Apple(info)构建的实现类
}
public class Apple{
    @Inject
    Apple(Info info){//被@Inject标记,使用这个构造器生成实例
        // ...
    }
    Apple(){   //不会使用这个构造器,没有被@Inject标记
    }
}

代码会生成 ComponentB 的实现类 DaggerComponetB,调用其 apple() 方法会自动使用 Apple(info) 构造器生成实例返回。

6、目标类(如 Container)中的@Inject 规则
1.该成员变量的依赖会从Module的@Provides方法集合中查找;
2.如果查找不到,则查找成员变量对应的类是否有@Inject构造方法,并注入构造方法且递归注入该类型的成员变量
7、Dagger2 中的单例

Java 中的单例通常保存在一个静态域中,这样的单例往往要等到虚拟机关闭的时候,该单例所占用的资源才释放。
但 Dagger2 创建出来的单例并不保持在静态域中,而是保留在 Component 实例中。

二、易错点

遇到的一些常见错误

1、Module 中存在多个返回相同类的@Provides 方法,导致 Component 依赖注入迷失

一个 Module 中,存在多个可以提供相同类的@Providers,编译时出错。

@Module
public class ActivityModule {

    @Provides
    public UserModel provideUserModel() {
        UserModel userModel = new UserModel();
        userModel.name = "default hacket";
        userModel.gender = "default gender male";
        return userModel;
    }

    @Provides
    public UserModel provideUserModel2() {
        UserModel userModel = new UserModel("hacket_2", "hacket_male_2");
        return userModel;
    }
}

错误如下:

Error:(17, 10) 错误: me.hacket.thirdpart.dagger2.demo2.ui.bean.UserModel is bound multiple times:
@Provides me.hacket.thirdpart.dagger2.demo2.ui.bean.UserModel me.hacket.thirdpart.dagger2.demo2.di.module.ActivityModule.provideUserModel()
@Provides me.hacket.thirdpart.dagger2.demo2.ui.bean.UserModel me.hacket.thirdpart.dagger2.demo2.di.module.ActivityModule.provideUserModel2()
@Provides me.hacket.thirdpart.dagger2.demo2.ui.bean.UserModel me.hacket.thirdpart.dagger2.demo2.di.module.ActivityModule.provideUserModel3()

解决,用@Qualifier 注解,在@Inject 和@Provides 标记一一对应起来。

2、Component 注入的对象不对(如为目标对象类的父类)

Component 中注入的对象不对,如注入 MainActivity,但是写了父类 Activity,编译不会出错,运行时注入的对象为 null。

@Component(modules = {ActivityModule.class})
public interface ActivityComponent {
    void injectUserModel(Activity activity);
}

注意: 这里必须是真正消耗依赖的类型 MainActivity,而不可以写成其父类,比如 Activity。因为 Dagger2 在编译时生成依赖注入的代码,会到 inject 方法的参数类型中寻找可以注入的对象,但是实际上这些对象存在于 MainActivity,而不是 Activity 中。如果函数声明参数为 Activity,Dagger2 会认为没有需要注入的对象。当真正在 MainActivity 中创建 Component 实例进行注入时,会直接执行按照 Activity 作为参数生成的 inject 方法,导致所有注入都失败。(是的,我是掉进这个坑了。)

3、命名@Provider 修饰的方法
Error:(32, 16) 错误: Cannot have more than one @Provides method with the same name in a single module
4、Scope 没有标记 Scope
Error:(14, 1) 错误: me.hacket.thirdpart.dagger2.demo4.component.JuiceComponent (unscoped) may not reference scoped bindings:
@Singleton @Provides me.hacket.thirdpart.dagger2.demo4.bean.JuiceMachine me.hacket.thirdpart.dagger2.demo4.module.MachineModule.provideJuiceMachine()

ListView 展示数据

UserAdapter

在构造方法前添加 @Inject 注解,这个 Dagger2 会在获取 UserAdapter 对象时,调用这个标记的构造方法,从而生成一个 UserAdapter 对象。

 public class UserAdapter extends BaseAdapter {
     private LayoutInflater inflater;
     private List<String> users;

     @Inject
     public UserAdapter(Context ctx, List<String> users) {
         this.inflater = LayoutInflater.from(ctx);
         this.users = users;
     }

     // ...
 }

如果构造方法含有参数,Dagger2 会在调用构造对象的时候先去获取这些参数,所以要保证它的参数也提供可被 Dagger 调用的生成函数。
Dagger2 调用生成对象的两种函数:

  1. 用@Inject 修饰的构造方法
  2. @Module 里用@Provides 修饰的方法

构建 Module

@Provides 提供给 UserAdapter 的两个参数 ContextList<String>,这样生成 UserAdapter 时需要的依赖从这里获取。

@Module
public class UserModule {
    private static final int COUNT = 30;
    private final Context mContext;
    @Inject
    public UserModule(Context context) {
        this.mContext = context;
    }
    @ActivityScope
    @Provides
    public Context provideActivityContext() {
        return mContext;
    }
    @ActivityScope
    @Provides
    public List<String> providerUsers() {
        List<String> users = new ArrayList<>(COUNT);

        for (int i = 0; i < COUNT; i++) {
            users.add("item " + i);
        }

        return users;
    }
}

构建 Component

负责注入依赖,@Component 生成实现并命名为 Dagger$${YouComponentClassName}

@ActivityScope
@Component(modules = {UserModule.class})
public interface UserComponent {
    void inject(Dagger2MainActivity activity);
}

注意:这里必须是真正消耗依赖的类型 MainActivity,而不可以写成其父类,比如 Activity ,否则会导致注入失败。

是一个自定义的范围注解,作用是允许对象被记录在正确的组件中,当然这些对象的生命周期应该遵循 Activity 的生命周期

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {

}

完成注入

 public class Dagger2MainActivity extends AppCompatActivity {
     // ...
     @Inject
     UserAdapter adapter;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         // ...
         // 完成注入
         DaggerUserComponent.builder()
             .userModule(new UserModule(this))
             .build()
             .inject(this);
         listView.setAdapter(adapter);
     }
 }

Reference

Dagger 2: Step To Step
http://www.jianshu.com/p/7505d92d7748

Dagger2 资源

Dagger2 基础

  1. Dagger 2从浅到深(一)
  2. Dagger 2从浅到深(二)
  3. Dagger 2从浅到深(三)
  4. Dagger 2从浅到深(四)
  5. Dagger 2从浅到深(五)
  6. Dagger 2从浅到深(六)
  7. Dagger 2从浅到深(七)
  8. Dagger 2应用于Android的完美扩展库-dagger.android

Dagger2 进阶

Android:dagger2 让你爱不释手 - 基础依赖注入框架篇
http://www.jianshu.com/p/cd2c1c9f68d4
Android:dagger2 让你爱不释手 - 重点概念讲解、融合篇
http://www.jianshu.com/p/1d42d2e6f4a5
Android:dagger2 让你爱不释手 - 终结篇
http://www.jianshu.com/p/65737ac39c44

Dagger2 原理

Dagger2 工作流程分析
http://ifarseer.github.io/2016/05/09/dagger2/

Dagger1 源码解析
http://a.codekk.com/detail/Android/扔物线/Dagger 源码解析

Dagger2 项目

https://github.com/saulmm/Avengers